import React, {Component} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
  Image,
  TouchableOpacity,
  Dimensions,
  AppState,
} from 'react-native';

import {
  Header,
  LearnMoreLinks,
  Colors,
  DebugInstructions,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

import {
  RTCPeerConnection,
  RTCIceCandidate,
  RTCSessionDescription,
  RTCView,
  MediaStream,
  MediaStreamTrack,
  mediaDevices,
  registerGlobals,
} from 'react-native-webrtc';

import SocketIO from 'socket.io-client';
import {Actions} from 'react-native-router-flux';

import Api from '../Api';

const dimension = Dimensions.get('window');
export default class VideoScreen extends Component {
  constructor(props) {
    super();
    this.size = {
      small: {
        width: 100,
        height: 100,
      },
      fullscreen: {
        width: '100%',
        height: '100%',
        top: 0,
      },
    };
    this.state = {
      isFront: false,
      pcs: {},
      streamSize: this.size.fullscreen,
      desktopSize: this.size.small,
    };
  }

  componentDidMount() {
    // 如果app切到后台，则退出页面
    AppState.addEventListener('change', appState => {
      if (appState === 'background') {
        Actions.pop();
      }
    });

    const {params} = this.props.navigation.state;
    // this.props.navigation.refresh({});
    this.setState({
      room: this.props.room,
    });

    this.getMedia();
    // global.nativeLoggingHook = 'error';
    const socket = new SocketIO(Api.SOCKET_URL, {
      // forceNode: true,
      transports: ['websocket']
    });
    socket
      .on('connect', () => {
        // socket.emit('connectionReady', socket.id);
      })
      .on('connectionReady', e => {
        // console.log('connectionReady', e);
      })
      .on('disconnection', e => {
        this.setState({
          remoteStream: null,
        });
      })
      .on('message', message => {
        if (message.to !== socket.id) {
          return;
        }
        // 收到A用户连接邀请
        if (message.type === 'offer') {
          const to = message.from;
          const sid = message.sid || Date.now().toString();
          const roomType = message.roomType;
          const broadcaster = socket.id;
          if (!this.nick) this.nick = message.payload.nick;
          delete message.payload.nick;
          const pc = this.pc(to, sid, roomType);
          pc.setRemoteDescription(new RTCSessionDescription(message.payload))
            .then(() => {
              // 回复A用户可以连接
              pc.createAnswer({
                offerToReceiveAudio: 1,
                offerToReceiveVideo: 1,
              })
                .then(desc => {
                  pc.setLocalDescription(desc).catch(e => {
                    console.log('answer error', e);
                  });
                  const msg = {
                    to: to,
                    sid: sid,
                    roomType: roomType,
                    type: 'answer',
                    payload: desc,
                  };

                  socket.emit('message', msg);
                })
                .catch(e => {
                  console.log('answer', e);
                });
            })
            .catch(e => {
              console.log('error', e, message);
            });
        } else if (message.type === 'answer') {
          // 收到A用户的应答
          const to = message.from;
          const sid = message.sid || Date.now().toString();
          const roomType = message.roomType;
          const broadcaster = socket.id;
          if (!this.nick) this.nick = message.payload.nick;
          delete message.payload.nick;
          const pc = this.pc(to, sid, roomType);
          pc.setRemoteDescription(
            new RTCSessionDescription(message.payload),
          ).catch(e => {
            console.log('answer error', e);
            this.setState({
              remoteStream: null,
            });
          });
        } else if (message.type === 'candidate') {
          // 远程发送了一个ICE候选地址信息给我们
          const to = message.from;
          const sid = message.sid;
          const roomType = message.roomType;
          const pc = this.pc(to, sid, roomType);
          pc.addIceCandidate(new RTCIceCandidate(message.payload.candidate));
        } else if (message.type === 'connectivityError') {
        } else if (message.type === 'mute') {
        } else if (message.type === 'unmute') {
        } else if (message.type === 'endOfCandidates') {
          // console.log(message);
          // this.state.pc.addIceCandidate("undefined");
        } else if (message.type === 'draw') {
          // console.log('message', message);
          this.setState({
            draw: message.payload,
          });
        }
      })
      .on('stunservers', args => {
        const turn = {
          urls: args[0].urls.replace('stun', 'turn'),
          username: 'couser',
          credential: 'Co@2019',
        };
        args.push(turn);
        // args[0].urls = 'stun:stun.xten.com';
        this.setState({
          servers: args,
        });
        socket.emit('join', this.state.room, (err, desc) => {
          const clients = Object.keys(desc.clients);
          if (clients.length) {
            for (var i = 0; i < clients.length; i++) {
              const client = clients[i];
              const to = client;
              const sid = Date.now().toString();
              const roomType = 'video';
              const pc = this.pc(to, sid, roomType);
              pc.createOffer({
                offerToReceiveAudio: 1,
                offerToReceiveVideo: 1,
              })
                .then(desc => {
                  pc.setLocalDescription(desc);
                  const msg = {
                    to,
                    sid,
                    roomType,
                    type: 'offer',
                    payload: desc,
                  };
                  socket.emit('message', msg);
                })
                .catch(e => {
                  console.log('createOffer error', e);
                });
            }
          }
          //   // console.log('join', roomDescription);
          //
        });
      })
      .on('remove', pc => {
        if (pc.type === 'screen') {
          this.setState({
            screenStream: null,
          });
        } else {
          this.setState({
            remoteStream: null,
          });
        }
      })
      .on('connect_error', error => {
        // alert(error);
        console.log('connect_error', error);
      })
      .on('error', error => {
        console.log('error', error);
      });

    // socket.joinNamespace(params.room);
    this.setState({
      socket,
    });
  }

  pc(to, sid, roomType) {
    const key = to + '-' + roomType;
    if (this.state.pcs[key]) {
      return this.state.pcs[key];
    }
    // RTCPeerConnection: 用于配置音频或视频聊天。RTCPeerConnection()构造函数，返回一个新建的  RTCPeerConnection实例，它代表了本地端机器与远端机器的一条连接。
    const pc = new RTCPeerConnection({
      iceServers: this.state.servers, // IceServer对象的数组，每个对象描述一个可以由ICE代理使用的服务器；这些通常是STUN和/或TURN服务器。
    });
    // 负责处理从远程计算机接收到的视频流的显示。
    pc.onaddstream = event => {
      if (roomType === 'screen') {
        this.setState({
          screenStream: event.stream,
        });
      } else {
        this.setState({
          remoteStream: event.stream,
        });
      }
    };
    pc.onremovestream = event => {
      console.log('remove stream');
      if (roomType === 'screen') {
        this.setState({
          screenStream: null,
        });
      } else {
        this.setState({
          screenStream: null,
        });
      }
    };
    pc.ondatachannel = event => {
      // console.log(event);
    };
    pc.onconnectionstatechange = event => {
      // console.log('onconnectionstatechange', event);
    };
    pc.onicecandidate = event => {
      if (event.candidate) {
        const msg = {
          to,
          sid,
          roomType,
          type: 'candidate',
          payload: {
            candidate: event.candidate,
          },
        };
        this.state.socket.emit('message', msg);
      } else {
        const msg = {
          to,
          sid,
          roomType,
          type: 'endOfCandidates',
        };
        this.state.socket.emit('message', msg);
      }
    };
    pc.onicecandidateerror = event => {
      // console.log('onicecandidateerror', event);
    };
    pc.oniceconnectionstatechange = event => {
      // console.log('oniceconnectionstatechange', event);
    };
    pc.onicegatheringstatechange = event => {
      // console.log('onicegatheringstatechange', event);
    };
    pc.onnegotiationneeded = event => {
      // console.log('onnegotiationneeded', event);
    };
    pc.onsignalingstatechange = event => {
      // console.log('onsignalingstatechange', event);
    };

    const {pcs} = this.state;
    pcs[key] = pc;
    // 使用getUserMedia()设置本地媒体流,并使用addstream()方法将其添加到RTCPeerConnection对象。
    if (this.state.stream) {
      pc.addStream(this.state.stream);
    }
    this.setState({pcs});
    return pc;
  }

  componentDidUpdate(prevProps, prevState) {
    // if (prevState && prevState.stream != this.state.stream) {
    // Object.values(this.state.pcs).forEach((item) => {
    // console.log(item);
    //   item.removeStream(prevState.stream);
    //   item.addStream(this.state.stream);
    // })
    // }
  }

  componentWillUnmount() {
    this.props.socket.emit('message', {
      to: this.props.hoster,
      from: this.props.socket.id,
      broadcaster: this.props.socket.id,
      type: 'hangup',
      roomType: 'message',
      playroad: {},
    });
    Object.values(this.state.pcs).forEach(item => {
      item.close();
    });
    this.state.socket ? this.state.socket.close() : null;
    // console.log(this.props);
  }

  // async getMedia() {
  //   const devices = await mediaDevices.enumerateDevices();
  //   const {isFront} = this.state;

  //   const facing = isFront ? 'front' : 'environment';
  //   const videoSourceId = devices.find(
  //     device => device.kind === 'videoinput' && device.facing === facing,
  //   );
  //   const facingMode = isFront ? 'user' : 'environment';
  //   const constraints = {
  //     audio: true,
  //     video: {
  //       mandatory: {
  //         width: dimension.width * dimension.scale, // Provide your own width, height and frame rate here
  //         height: dimension.height * dimension.scale,
  //         minFrameRate: 30,
  //       },
  //       facingMode,
  //       optional: videoSourceId ? [{sourceId: videoSourceId}] : [],
  //     },
  //   };
  //   const newStream = await mediaDevices.getUserMedia(constraints);
  //   this.setState({
  //     localStream: newStream,
  //   });
  // }

  getMedia() {
    mediaDevices.enumerateDevices().then(sourceInfos => {
      let videoSourceId;
      for (let i = 0; i < sourceInfos.length; i++) {
        const sourceInfo = sourceInfos[i];
        if (
          sourceInfo.kind == 'videoinput' &&
          sourceInfo.facing == (this.state.isFront ? 'front' : 'back')
        ) {
          videoSourceId = sourceInfo.deviceId;
        }
      }
      // getUserMedia: 1.开发人员可以访问视频和音频流对象 2.访问用户麦克风和摄像头
      mediaDevices
        .getUserMedia({
          audio: true,
          video: {
            mandatory: {
              width: dimension.width * dimension.scale, // Provide your own width, height and frame rate here
              height: dimension.height * dimension.scale,
              minFrameRate: 30,
            },
            facingMode: this.state.isFront ? 'user' : 'environment',
            optional: videoSourceId ? [{sourceId: videoSourceId}] : [],
          },
        })
        .then(stream => {
          // 实时视频或音频以流对象的形式表示。
          this.setState({
            stream,
          });
        })
        .catch(error => {
          // alert(error);
          // Log error
        });
    });
  }

  switchCamera() {
    let {isFront, stream} = this.state;
    isFront = !isFront;

    this.setState({isFront});
    // this.getMedia();
    stream.getVideoTracks().forEach(v => {
      v._switchCamera();
    });
  }

  hangup() {
    const {socket} = this.state;
    this.props.socket.emit('message', {
      to: this.props.hoster,
      from: this.props.socket.id,
      broadcaster: this.props.socket.id,
      type: 'hangup',
      roomType: 'message',
      playroad: {},
    });
  }

  render() {
    return (
      <View>
        <StatusBar barStyle="light-content" backgroundColor="#5096fc" />
        <SafeAreaView>
          <View>
            <Image
              source={
                !this.state.isFront
                  ? {
                      uri: this.state.draw,
                    }
                  : null
              }
              style={{
                position: 'absolute',
                width: '100%',
                height: '100%',
                zIndex: 999,
              }}
            />
            <RTCView
              streamURL={this.state.stream ? this.state.stream.toURL() : null}
              objectFit="cover"
              mirror={this.state.isFront}
              style={this.state.streamSize}
            />
            {this.state.remoteStream ? (
              <RTCView
                streamURL={this.state.remoteStream.toURL()}
                style={{
                  position: 'absolute',
                  width: 100,
                  height: 100,
                  zIndex: 1001,
                }}
              />
            ) : null}
            {this.state.screenStream ? (
              <TouchableOpacity
                style={{
                  position: 'absolute',
                  top:
                    this.state.desktopSize.width === this.size.fullscreen.width
                      ? this.state.desktopSize.top
                      : 110,
                  width: this.state.desktopSize.width,
                  height: this.state.desktopSize.height,
                  zIndex: 1000,
                }}
                onPress={() => {
                  this.setState({
                    desktopSize:
                      this.state.desktopSize.width ===
                      this.size.fullscreen.width
                        ? this.size.small
                        : this.size.fullscreen,
                  });
                }}>
                <RTCView
                  style={this.size.fullscreen}
                  streamURL={this.state.screenStream.toURL()}
                />
              </TouchableOpacity>
            ) : null}
          </View>
        </SafeAreaView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: Colors.lighter,
  },
  engine: {
    position: 'absolute',
    right: 0,
  },
  body: {
    backgroundColor: Colors.white,
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
    color: Colors.black,
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
    color: Colors.dark,
  },
  highlight: {
    fontWeight: '700',
  },
  footer: {
    color: Colors.dark,
    fontSize: 12,
    fontWeight: '600',
    padding: 4,
    paddingRight: 12,
    textAlign: 'right',
  },
});
